#include "iuOSWindows.h"


#pragma comment( lib, "User32.lib" )

using namespace Pure;
using namespace Pure::System;
using namespace Pure::System::OS;


typedef void (__stdcall* LPNATIVESYSTEMINFO)(SYSTEM_INFO*);
typedef BOOL (__stdcall* LPGETPRODUCTINFO)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long*);


iuOSWindows::iuOSWindows( void ) : iuOSBase( Corporation::Microsoft, Platform::Windows )
{
	memset( &mPlatformVersion, 0, sizeof( mPlatformVersion ) );	
	mProductType = ProductType::None;	
	memset( &mServicePackVersion, 0, sizeof( mServicePackVersion ) );	
	mBuildNumber = 0;	
	mProcessorArchitecture = ProcessorArchitecture::None;
}


iuOSWindows::~iuOSWindows( void )
{
}


bool iuOSWindows::Checking( void )
{
	OSVERSIONINFOEX osVersionInfoEx;
	SYSTEM_INFO systemInfo;
	LPNATIVESYSTEMINFO lpGetNativeSystemInfo;
	//PGPI pGPI;
	//unsigned long ulType( 0 );

	memset( &osVersionInfoEx, 0, sizeof( osVersionInfoEx ) );
	memset( &systemInfo, 0, sizeof( systemInfo ) );	
	osVersionInfoEx.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX );


	if( GetVersionEx( (OSVERSIONINFO*)&osVersionInfoEx ) )
	{
		if( lpGetNativeSystemInfo = (LPNATIVESYSTEMINFO)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "GetNativeSystemInfo" ) )
		{
			lpGetNativeSystemInfo( &systemInfo );
		}
		else
		{
			GetSystemInfo( &systemInfo );
		}


		RunChecking( osVersionInfoEx, systemInfo );


		return true;
	}


	return false;
}


void iuOSWindows::RunChecking( const OSVERSIONINFOEX& osvi, const SYSTEM_INFO& si )
{
	//! set product type
	SetProductType( osvi.wProductType );

	//! set major/minor version
	SetPlatformVersion( osvi.dwMajorVersion, osvi.dwMinorVersion );

	//! service pack version
	SetServicePackVersion( osvi.wServicePackMajor, osvi.wServicePackMinor );

	//! set build number
	SetBuildNumber( osvi.dwBuildNumber );

	//! processor architecture
	SetProcessorArchitecture( si.wProcessorArchitecture );
}


void iuOSWindows::SetProductType( unsigned char productType )
{
	switch( productType )
	{
	case VER_NT_WORKSTATION :
		{
			mProductType = ProductType::Workstation;
		}
		break;

	case VER_NT_DOMAIN_CONTROLLER :
	case VER_NT_SERVER :
		{
			mProductType = ProductType::Server;
		}
		break;
	}
}


void iuOSWindows::SetPlatformVersion( unsigned long major, unsigned long minor )
{
	//! set major version
	if( ( MIN_MAJOR_VERSION <= major ) && ( MAX_MAJOR_VERSION >= major ) )
	{
		mPlatformVersion.majorVersion = major;
	}


	//! set minor version
	unsigned long minVersion( 0 ), maxVersion( 0 );

	switch( major )
	{
	case NT5::MajorVersion :
		{
			minVersion = NT5::Version_0;
			maxVersion = NT5::Version_2;
		}
		break;

	case NT6::MajorVersion :
		{
			minVersion = NT6::Version_0;
			maxVersion = NT6::Version_2;
		}
		break;

	default :
		break;
	}

	if( ( minVersion <= minor ) && ( maxVersion >= minor ) )
	{
		mPlatformVersion.minorVersion = minor;
	}
}


void iuOSWindows::SetBuildNumber( unsigned long buildNumber )
{
	if( 0 <= buildNumber )
	{
		mBuildNumber = buildNumber;
	}
}


void iuOSWindows::SetServicePackVersion( const unsigned short major, const unsigned short minor )
{
	//! set major version
	if( 0 <= major )
	{
		mServicePackVersion.majorVersion = major;
	}


	//! set minor version
	if( 0 <= minor )
	{
		mServicePackVersion.minorVersion = minor;
	}
}


void iuOSWindows::SetProcessorArchitecture( unsigned short processorArchitecture )
{
	if( NT6::MajorVersion <= mPlatformVersion.majorVersion )
	{
		switch( processorArchitecture )
		{
		case PROCESSOR_ARCHITECTURE_INTEL :
			{
				mProcessorArchitecture = ProcessorArchitecture::x86;
			}
			break;

		case PROCESSOR_ARCHITECTURE_AMD64 :
			{
				mProcessorArchitecture = ProcessorArchitecture::x64;
			}
			break;
		}
	}
}